package com.util;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.security.DigestInputStream;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.Security;
import java.text.SimpleDateFormat;
import java.util.Date;

import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;

public class MD5Util {
	
	/**
	 * 默认的密码字符串组合，apache校验下载的文件的正确性用的就是默认的这个组合
	 */
	protected static char hexDigits[] = { '0', '1', '2', '3', '4', '5', '6',
			'7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
	protected static MessageDigest messagedigest = null;
	static {
		try {
			messagedigest = MessageDigest.getInstance("MD5");
		} catch (NoSuchAlgorithmException nsaex) {
			System.err.println(MD5Util.class.getName()
					+ "初始化失败，MessageDigest不支持 MD5Util。");
			nsaex.printStackTrace();
		}
	}

	
	/**
	 * 适用于上G大的文件
	 * 
	 * @param file
	 * @return
	 * @throws IOException
	 */
	public static String getFileMD5String(File file) throws IOException {
		FileInputStream in = new FileInputStream(file);
		FileChannel ch = in.getChannel();
		MappedByteBuffer byteBuffer = ch.map(FileChannel.MapMode.READ_ONLY, 0,
				file.length());
		messagedigest.update(byteBuffer);
		String result = bufferToHex(messagedigest.digest());
		ch.close();
		in.close();
		return result;
	}
	
	public static String getFileMD5(File file) throws Exception
	{
			// 缓冲区大小（这个可以抽出一个参数）
			int bufferSize = 1024 * 1024;
			FileInputStream fileInputStream = null;
			DigestInputStream digestInputStream = null;
			try {
				// 拿到一个MD5转换器（同样，这里可以换成SHA1）
				MessageDigest messageDigest = MessageDigest.getInstance("MD5");
				// 使用DigestInputStream
				fileInputStream = new FileInputStream(file);
				digestInputStream = new DigestInputStream(fileInputStream,
						messageDigest);
				// read的过程中进行MD5处理，直到读完文件
				byte[] buffer = new byte[bufferSize];
				while (digestInputStream.read(buffer) > 0)
					;
				// 获取最终的MessageDigest
				messageDigest = digestInputStream.getMessageDigest();
				// 拿到结果，也是字节数组，包含16个元素
				byte[] resultByteArray = messageDigest.digest();
				// 同样，把字节数组转换成字符串
				return bufferToHex(resultByteArray);
			} catch (NoSuchAlgorithmException e) {
				return null;
			} finally {
				try {
					digestInputStream.close();
				} catch (Exception e) {
				}
				try {
					fileInputStream.close();
				} catch (Exception e) {
				}
			}
	}

	public static String getMD5String(String s) {
		return getMD5String(s.getBytes());
	}

	public static String getMD5String(byte[] bytes) {
		messagedigest.update(bytes);
		return bufferToHex(messagedigest.digest());
	}

	private static String bufferToHex(byte bytes[]) {
		return bufferToHex(bytes, 0, bytes.length);
	}

	private static String bufferToHex(byte bytes[], int m, int n) {
		StringBuffer stringbuffer = new StringBuffer(2 * n);
		int k = m + n;
		for (int l = m; l < k; l++) {
			appendHexPair(bytes[l], stringbuffer);
		}
		return stringbuffer.toString();
	}

	private static void appendHexPair(byte bt, StringBuffer stringbuffer) {
		char c0 = hexDigits[(bt & 0xf0) >> 4];
		char c1 = hexDigits[bt & 0xf];
		stringbuffer.append(c0);
		stringbuffer.append(c1);
	}

	public static boolean checkPassword(String password, String md5PwdStr) {
		String s = getMD5String(password);
		return s.equals(md5PwdStr);
	}
	
	
	// 解密
	static public String jiemi(String src) {
		// 密钥
		Date date = new Date();
		SimpleDateFormat sdf = new SimpleDateFormat("yyyy-dd-MM");
		String now = sdf.format(date);
		String Password = MD5Util.getMD5(now).substring(0,24);
		// String Password = MD5.md5_24(pwd);
		// String Password = ;
		String Algorithm = "DESede";
		byte KeyBytes[] = new byte[24];
		byte PassBytes[] = Password.getBytes();

		for (int i = 0; i < 24; i++) {
			if (i < PassBytes.length)
				KeyBytes[i] = PassBytes[i];
			else
				KeyBytes[i] = 0x30;
		}
		// 还原
		byte[] b = hexStringToBytes(src);
		Security.addProvider(new com.sun.crypto.provider.SunJCE());
		SecretKey DesKey = new SecretKeySpec(KeyBytes, Algorithm);

		try {
			Cipher C = Cipher.getInstance(Algorithm);
			C.init(Cipher.DECRYPT_MODE, DesKey);
			byte Encrypt[] = C.doFinal(b);

			return new String(Encrypt);
		} catch (Exception e) {
			
		}

		return null;

	}

	
	
	public static String jiami(String str) {
		String AuthStr = str;
		String Result = "";
		try {

			Date date = new Date();
			SimpleDateFormat sdf = new SimpleDateFormat("yyyy-dd-MM");
			String now = sdf.format(date);
			String Password = MD5Util.getMD5(now).substring(0,24);

			byte Auth[] = AuthStr.getBytes("ASCII");
			int Len = Auth.length;
			int Mod = Len % 8;

			if (Mod != 0)
				Len += 8 - Mod;
			byte AuthBytes[] = new byte[Len];

			for (int i = 0; i < Len; i++) {
				if (i >= Auth.length)
					AuthBytes[i] = (byte) (8 - Mod);
				else
					AuthBytes[i] = Auth[i];
			}

			String Algorithm = "DESede";
			byte KeyBytes[] = new byte[24];
			byte PassBytes[] = Password.getBytes();

			for (int i = 0; i < 24; i++) {
				if (i < PassBytes.length)
					KeyBytes[i] = PassBytes[i];
				else
					KeyBytes[i] = 0x30;
			}

			Security.addProvider(new com.sun.crypto.provider.SunJCE());
			SecretKey DesKey = new SecretKeySpec(KeyBytes, Algorithm);

			Cipher C = Cipher.getInstance(Algorithm);
			C.init(Cipher.ENCRYPT_MODE, DesKey);
			byte Encrypt[] = C.doFinal(AuthBytes);

			for (int i = 0; i < Len; i++) {
				Result += String.format("%02X",
						Encrypt[i] < 0 ? (256 + Encrypt[i]) : Encrypt[i]);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}

		return Result;
	}
	
	public static byte[] hexStringToBytes(String hexString) {

		if (hexString == null || hexString.equals("")) {

			return null;

		}

		hexString = hexString.toUpperCase();

		int length = hexString.length() / 2;

		char[] hexChars = hexString.toCharArray();

		byte[] d = new byte[length];

		for (int i = 0; i < length; i++) {

			int pos = i * 2;

			d[i] = (byte) (charToByte(hexChars[pos]) << 4 | charToByte(hexChars[pos + 1]));

		}

		return d;
	}


	
	private static String byteHEX(byte ib) {
		char[] Digit = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A',
				'B', 'C', 'D', 'E', 'F' };
		char[] ob = new char[2];
		ob[0] = Digit[(ib >>> 4) & 0X0F];
		ob[1] = Digit[ib & 0X0F];
		String s = new String(ob);
		return s;
	}
	
	private static byte charToByte(char c) {

		return (byte) "0123456789ABCDEF".indexOf(c);
	}
	
//字符串加密	
   public static String getMD5(String source){
	   MessageDigest messageDigest = null;
	try {
		messageDigest = MessageDigest.getInstance("MD5");
	} catch (NoSuchAlgorithmException e) {
		// TODO Auto-generated catch block
		e.printStackTrace();
	}
       messageDigest.update(source.getBytes());
       byte[] b = messageDigest.digest();
       StringBuffer sb = new StringBuffer();
       for (int i=0;i<b.length;i++){
      	 sb.append(byteHEX(b[i]));
       }
       
       //sb.setCharAt(sb.length()-1, (char)(sb.charAt(sb.length()-1)+1));
       return sb.toString();
   }
}
